import axios, { type AxiosInstance } from 'axios';
import * as cheerio from 'cheerio';
import { EventEmitter } from 'events';

/**
 * 抓取进度事件
 */
export interface ScrapingProgress {
  stage: string;
  current: number;
  total: number;
  item?: string;
  message?: string;
}

/**
 * 抓取结果基础接口
 */
export interface ScrapingResult {
  success: boolean;
  count: number;
  data: any[];
  errors: string[];
  timestamp: Date;
  duration: number;
}

/**
 * 数据抓取器基类
 */
export abstract class BaseScraper extends EventEmitter {
  protected httpClient: AxiosInstance;
  protected baseUrl: string;
  protected name: string;
  protected rateLimitDelay: number = 1000; // 1秒延迟
  protected maxRetries: number = 3;
  protected retryDelay: number = 2000; // 重试延迟
  protected timeout: number = 10000; // 10秒超时

  constructor(name: string, baseUrl: string) {
    super();
    this.name = name;
    this.baseUrl = baseUrl;
    this.httpClient = axios.create({
      baseURL: baseUrl,
      timeout: this.timeout,
      headers: {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate',
        'Connection': 'keep-alive',
      },
    });

    this.setupInterceptors();
  }

  /**
   * 设置HTTP拦截器
   */
  private setupInterceptors(): void {
    this.httpClient.interceptors.request.use(
      (config) => {
        this.log(`🌐 请求: ${config.method?.toUpperCase()} ${config.url}`);
        return config;
      },
      (error) => {
        this.error(`❌ 请求错误: ${error.message}`);
        return Promise.reject(error);
      }
    );

    this.httpClient.interceptors.response.use(
      (response) => {
        this.log(`✅ 响应: ${response.status} ${response.config.url}`);
        return response;
      },
      (error) => {
        this.error(`❌ 响应错误: ${error.response?.status} ${error.config?.url}`);
        return Promise.reject(error);
      }
    );
  }

  /**
   * 执行抓取任务
   */
  abstract scrape(): Promise<ScrapingResult>;

  /**
   * 获取页面HTML内容
   */
  protected async fetchPage(url: string, retries: number = 0): Promise<string> {
    try {
      const response = await this.httpClient.get(url);
      return response.data;
    } catch (error) {
      if (retries < this.maxRetries) {
        this.warn(`⚠️  重试 ${retries + 1}/${this.maxRetries}: ${url}`);
        await this.delay(this.rateLimitDelay * (retries + 1));
        return this.fetchPage(url, retries + 1);
      }
      throw error;
    }
  }

  /**
   * 获取JSON数据
   */
  protected async fetchJson(url: string, retries: number = 0): Promise<any> {
    try {
      const response = await this.httpClient.get(url, {
        headers: { 'Accept': 'application/json' }
      });
      return response.data;
    } catch (error) {
      if (retries < this.maxRetries) {
        this.warn(`⚠️  重试 ${retries + 1}/${this.maxRetries}: ${url}`);
        await this.delay(this.rateLimitDelay * (retries + 1));
        return this.fetchJson(url, retries + 1);
      }
      throw error;
    }
  }

  /**
   * 解析HTML内容
   */
  protected parseHtml(html: string): cheerio.CheerioAPI {
    return cheerio.load(html);
  }

  /**
   * 延迟执行
   */
  protected async delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 发出进度事件
   */
  protected emitProgress(progress: ScrapingProgress): void {
    this.emit('progress', progress);
    this.log(`📊 进度: ${progress.stage} ${progress.current}/${progress.total} ${progress.message || ''}`);
  }

  /**
   * 记录日志
   */
  protected log(message: string): void {
    console.log(`[${this.name}] ${message}`);
  }

  /**
   * 记录警告
   */
  protected warn(message: string): void {
    console.warn(`[${this.name}] ${message}`);
  }

  /**
   * 记录错误
   */
  protected error(message: string): void {
    console.error(`[${this.name}] ${message}`);
  }

  /**
   * 清理URL，确保绝对路径
   */
  protected normalizeUrl(url: string): string {
    if (url.startsWith('http')) {
      return url;
    }
    if (url.startsWith('//')) {
      return `https:${url}`;
    }
    if (url.startsWith('/')) {
      return `${this.baseUrl}${url}`;
    }
    return `${this.baseUrl}/${url}`;
  }

  /**
   * 提取文本内容并清理
   */
  protected cleanText(text: string): string {
    return text
      .replace(/\s+/g, ' ')
      .replace(/[\r\n\t]/g, ' ')
      .trim();
  }

  /**
   * 验证必需字段
   */
  protected validateRequired(obj: any, fields: string[]): boolean {
    return fields.every(field => obj[field] && obj[field].trim().length > 0);
  }

  /**
   * 生成唯一标识符
   */
  protected generateId(text: string): string {
    return text.toLowerCase()
      .replace(/[^a-z0-9]/g, '-')
      .replace(/-+/g, '-')
      .replace(/^-|-$/g, '');
  }

  /**
   * 安全执行函数，捕获异常
   */
  protected async safeExecute<T>(
    fn: () => Promise<T>,
    fallback: T,
    context: string
  ): Promise<T> {
    try {
      return await fn();
    } catch (error) {
      this.error(`${context}: ${error instanceof Error ? error.message : String(error)}`);
      return fallback;
    }
  }
}